#pragma once

#include <deque>
#include "NetUtil.h"
#include "Package.h"
#include "Define.h"
#include "BufferShrink.h"

namespace wsbus {


	class SessionInfo
	{
	public:
		void setApp(int appType, int sessionId);
		void updateSubscribe(int type, const std::vector<std::string> &cmdList);
		int appType() const { return appType_; }
		int sessionId() const { return sessionId_; }
		bool isSubscibe(const std::string &cmd) const;

	private:
		int appType_{ atBus };
		unsigned short sessionId_{ 0 };
		std::set<std::string> subscibeList_;
		mutable std::mutex mutex_;
	};

	class SessionParent
	{
	public:
		virtual ~SessionParent() {}
		virtual int deliver(const PackagePtr &msg) = 0;
		virtual const SessionInfo& info() const = 0;
	};

	typedef std::shared_ptr<SessionParent> SessionParentPtr;

	class Dispatcher;
	class Session : public SessionParent, public std::enable_shared_from_this<Session>
	{
	public:
#ifdef WS_SSL
		Session(tcp::socket socket, ssl::context &sslctx, Dispatcher &dispatcher);
#else
		Session(tcp::socket socket, Dispatcher &dispatcher);
#endif
		void start();
		int deliver(const PackagePtr &msg) override;
		const SessionInfo& info() const override { return info_; }

	private:
#ifdef WS_SSL
		void onStart();
		void onSSLHandshake(beast::error_code ec);
#endif
		void onAccept(boost::system::error_code ec);
		void doRead();
		void onRead(beast::error_code ec, std::size_t bytesTransferred);
		void doWrite();
		void onWrite(beast::error_code ec, std::size_t bytesTransferred);
		void onDeliver(const PackagePtr &msg);
		void onHandleInternal(const PackagePtr &msg);
		void responseMessage(const PackagePtr &request, const MoreMessagePtr &responseMsg);
		void responseCommonMessage(const PackagePtr &request, int errorCode, const std::string &errorMsg);
		static unsigned short newSessionId();

	private:
		SessionInfo info_;
#ifdef WS_SSL
		websocket::stream<beast::ssl_stream<beast::tcp_stream>> ws_;
#else
		websocket::stream<tcp::socket> ws_;
#endif
		beast::flat_buffer writeBuffer_;
		beast::flat_buffer readBuffer_;
		BufferShrink writeBufferShrink_;
		BufferShrink readBufferShrink_;
		Dispatcher &dispatcher_;
		std::deque<PackagePtr> writeMessages_;
	};

}


